package frontend.pages.admin.base;

import backend.model.base.DBModel;
import backend.service.base.DBModelService;
import frontend.components.form.ButtonsBehavior;
import frontend.components.form.SaveDeleteButtonsPanel;
import frontend.components.form.ValidatableForm;
import frontend.core.TimeTrackingWebApplication;
import frontend.model.base.UIModel;
import shared.util.CalendarUtils;
import org.apache.log4j.Logger;
import org.apache.wicket.Localizer;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.request.mapper.parameter.PageParameters;
import org.apache.wicket.validation.ValidationError;
import org.springframework.dao.DataIntegrityViolationException;

public abstract class AbstractManagingForm<UIM extends UIModel> extends ValidatableForm<UIM> {
    private static Logger logger = Logger.getLogger(AbstractManagingForm.class);

    private static final String RESOURCE_KEY_VALIDATION_FORM_GENERIC_CANNOT_DELETE_BECAUSE_IN_USE = "validation.form.generic.cannotDeleteBecauseInUse";
    public static final String RESOURCE_KEY_INFO_ENTITY_SAVED_SUCCESSFULLY = "info.entity.saved.successfully";
    public static final String RESOURCE_KEY_INFO_ENTITY_DELETED_SUCCESSFULLY = "info.entity.deleted.successfully";
    public static final String PAGE_PARAMETER_KEY_OPERATION_SUCCESSFUL = "saveMsg";


    public AbstractManagingForm(String id, UIM uiModel) {
        super(id, uiModel);
        constructButtons();
    }

    protected void constructButtons() {
        SaveDeleteButtonsPanel buttonsPanel = new SaveDeleteButtonsPanel("saveDeleteButtons",
                new ButtonsBehavior() {
                    @Override
                    public void onSave(AjaxRequestTarget target) {
                        boolean success = save();
                        if (success) {
                            postSave(target);
                        }
                        target.add(feedbackPanel);
                    }

                    @Override
                    public void onDelete(AjaxRequestTarget target) {
                        boolean success = delete();
                        if (success) {
                            postDelete(target);
                        }
                        target.add(feedbackPanel);
                    }

                    @Override
                    public void onError(AjaxRequestTarget target) {
                        target.add(feedbackPanel);
                    }

                    @Override
                    public boolean isDeleteButtonVisible() {
                        return AbstractManagingForm.this.isDeleteButtonVisible();
                    }

                    @Override
                    public boolean isSaveButtonVisible() {
                        return true;
                    }
                });

        add(buttonsPanel);
    }

    protected boolean save() {
        validationErrors.clear();
        doFormValidation();

        if (validationErrors.size() > 0) {
            for (ValidationError validationError : validationErrors) {
                error(validationError.getMessage());
            }
        } else {
            uiModel.populateDBModelFromFields();
            DBModel dbModel = uiModel.getDBModel();
            logger.info("Saving entity: [" + dbModel.getClass() + "] - " + dbModel.getDisplayLabel());
            saveOrUpdateDBModel(dbModel);
            return true;
        }
        return false;
    }

    /**
     * Override this method in order to do some custom actions after a successful save
     */
    protected void postSave(AjaxRequestTarget target) {
        setResponsePage(getResponsePage(), new PageParameters().add(PAGE_PARAMETER_KEY_OPERATION_SUCCESSFUL,
                CalendarUtils.appendCurrentTime(Localizer.get().getString(RESOURCE_KEY_INFO_ENTITY_SAVED_SUCCESSFULLY, null))));
    }

    protected boolean delete() {
        DBModel dbModel = uiModel.getDBModel();
        DBModelService service = TimeTrackingWebApplication.getServiceByDBModel(dbModel.getClass());
        logger.info("Deleting entity: [" + dbModel.getClass() + "] - " + dbModel.getDisplayLabel());
        try {
            service.deleteDBModel(dbModel);
        } catch (DataIntegrityViolationException dive) {
            ValidationError validationError = createValidationError(RESOURCE_KEY_VALIDATION_FORM_GENERIC_CANNOT_DELETE_BECAUSE_IN_USE);
            error(validationError.getMessage());
            return false;
        }
        return true;
    }

    /**
     * Override this method in order to do some custom actions after a successful delete
     */
    protected void postDelete(AjaxRequestTarget target) {
        setResponsePage(getResponsePage(), new PageParameters().add(PAGE_PARAMETER_KEY_OPERATION_SUCCESSFUL,
                CalendarUtils.appendCurrentTime(Localizer.get().getString(RESOURCE_KEY_INFO_ENTITY_DELETED_SUCCESSFULLY, null))));
    }

    protected boolean isDeleteButtonVisible() {
        return uiModel.getDBModel().getId() > 0;
    }

    private void saveOrUpdateDBModel(DBModel dbModel) {
        DBModelService service = TimeTrackingWebApplication.getServiceByDBModel(dbModel.getClass());
        service.saveOrUpdateDBModel(dbModel);
    }

    protected abstract void constructFormContent();
    protected abstract Class getResponsePage();
}
